iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
Modern Web

就是個Go,我也可以啦!GOGO系列 第 6

2023鐵人賽Day 6 Go X 介面

  • 分享至 

  • xImage
  •  

什麼是介面(interfaces)

An interface in Go is a type defined using a set of method signatures.

golang的教程寫了這一句,翻譯就是,介面是一種特殊的類型,由一組方法簽名定義。
為什麼要用簽名,簽名定義了方法的結構,但不涉及方法的實現

  • 介面:當你定義介面時,可以把介面想成一個合同,在合同中有一些規則或任務(方法),但合同本身不告訴你如何完成這些任務
  • 方法簽名:當你定義介面時,方法簽名由方法名稱和一個引數列表組成,引數列表定義了方法的參數順序和型別。這個簽名定義了方法的“形狀”或結構,但不包括方法的具體實現或行為
  • 介面隱式實現: 當你使用介面時,一個類型通過實現其方法來實現介面。沒有顯式聲明的意圖,也沒有 "implements" 關鍵字,隱式介面將介面的定義與其實現分開,這樣實現就可以出現在任何包中,無需事先安排。

隱式介面將介面的定義與其實現分開,這樣實現就可以出現在任何包中,無需事先安排。

定義的介面

type Reader interface {
	Read(p []byte) (n int, err error)
}

定義介面時

type Xxxer interface {
  method(value, type)
}

定義介面時.會描述一組方法簽名,一個method就是一個方法簽名,這些簽名會定義這個介面期望的期望行為,例如,你可能會定義一個Writer介面,只包括一個Write方法

type Writer interface {
    Write([]byte) (int, error)
}
  • 關鍵字type,接下來是介面名稱(動詞),接下來是關鍵字interface
  • 慣例上介面名稱會拿其中一個方法名稱加上er結尾

實現介面

1. 介面的使用時機

使用介面

當你希望多個類型共享相同的行為時,你可以使用介面。例如,你可以定義一個 Speaker 介面,用於所有可以"說話"的物件。

type Speaker interface {
	Speak() string
}

type Dog struct{}
func (d Dog) Speak() string { return "Woof!" }

type Cat struct{}
func (c Cat) Speak() string { return "Meow!" }

func AnimalSpeak(a Speaker) {
	fmt.Println(a.Speak())
}

func main() {
	d := Dog{}
	c := Cat{}
	AnimalSpeak(d) // 輸出:Woof!
	AnimalSpeak(c) // 輸出:Meow!
}
 +------------+       +------------+
 |  Speaker   |<------|    Dog     |
 +------------+       +------------+
 | Speak()    |       | Speak()    |
 +------------+       +------------+
        ^
        |
 +------------+
 |    Cat     |
 +------------+
 | Speak()    |
 +------------+

d := Dog{}
c := Cat{}
AnimalSpeak(d) // 輸出:Woof!
AnimalSpeak(c) // 輸出:Meow!

這個示例代碼與 UML 圖一起描述了 DogCat 類型如何通過實現 Speaker 介面來共享相同的行為,並且如何在主函數中調用這些行為。你可以在 AnimalSpeak 函數中傳入任何實現了 Speaker 介面的類型,它將通過調用該類型的 Speak 方法來輸出對應的聲音。

不使用介面

如果你的類型不需要共享行為,那麼你不需要使用介面。

type Dog struct{}
func (d Dog) Bark() string { return "Woof!" }

func main() {
	d := Dog{}
	fmt.Println(d.Bark()) // 輸出:Woof!
}

2. 結構的使用時機

使用結構

當你需要組合多個字段時,可以使用結構。

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{Name: "Alice", Age: 30}
	fmt.Println(p.Name, p.Age) // 輸出:Alice 30
}

不使用結構

如果你只有一個值,你不需要結構。

type Age int

func main() {
	var a Age = 30
	fmt.Println(a) // 輸出:30
}

3. 方法的使用時機

有接收者的方法

當你想要為特定類型定義行為時,你可以使用方法。

type Circle struct {
	Radius float64
}

func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

func main() {
	c := Circle{Radius: 5}
	fmt.Println(c.Area()) // 輸出半徑為5的圓的面積
}

沒有接收者的函數

如果函數不依賴於特定類型,那麼它是一個普通函數。

func Add(x, y int) int {
	return x + y
}

func main() {
	fmt.Println(Add(3, 4)) // 輸出:7
}

上一篇
2023鐵人賽Day 5 Go X 方法
下一篇
2023鐵人賽Day 7 Go設計哲學-1
系列文
就是個Go,我也可以啦!GOGO30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言